<template>
  <div class="main">
    <div v-if="showCheck"
         class="input-container">
      <div>
        value最小值：
        <a-input-number v-model:value="num"
                        size="small"
                        :min="1"
                        @change="handleChange" />
      </div>
      <div>
        <a-checkbox v-if="showLevel"
                    v-model:checked="checked"
                    @change="handleCheck">展示第九层选项</a-checkbox>
      </div>
    </div>
    <div v-if="hasType"
         class="tip">致病源分类：<div id="legend"></div>
    </div>
    <div id="sankey"
         ref="sankey"
         :style="{ height, width }"
         :class="`sankey ${showCheck || hasType ? 'sankey-margin-top' : ''}`" />
  </div>
</template>

<script lang="ts">
import { defineComponent, ref, unref, onMounted, onUnmounted, PropType, watch } from 'vue';
import * as echarts from 'echarts';
import * as d3 from 'd3';

const colors = ['#ff1403', '#5b03f7'];

const labelName = ['致病源', '条件致病源'];

const labelTip: string[] = [];

const color = d3.scaleOrdinal().domain(labelName).range(colors);

const legend = (svg: any) => {
  const g = svg
    .selectAll('g')
    .data(color.domain())
    .join('g')
    .attr('transform', (d: any, i: number) => `translate(${i * 150}, 0)`);

  g.append('title').text((d: any, i: number) => labelTip[i]);
  g.append('rect').attr('width', 120).attr('height', 20).attr('fill', color);
  g.append('text')
    .attr('x', 60)
    .attr('y', 12)
    .text((d: any) => d)
    .attr('fill', '#fff')
    .attr('text-anchor', 'middle')
    .attr('dominant-baseline', 'middle');
};

export default defineComponent({
  props: {
    type: {
      type: String,
      default: undefined,
    },
    width: {
      type: String as PropType<string>,
      default: '100%',
    },
    height: {
      type: String as PropType<string>,
      default: '800px',
    },
    // 数据源
    dataSet: {
      type: Object as PropType<{ nodes: any[]; links: any[] }>,
      default: { nodes: [], links: [] },
    },
    // 致病原分类
    sankeyType: {
      type: Object as any,
      default: {},
    },
    // 是否显示分类
    hasType: {
      type: Boolean,
      default: true,
    },
    // 是否显示选中
    showCheck: {
      type: Boolean,
      default: true,
    },
    // 是否展示第九层选项
    showLevel: {
      type: Boolean,
      default: false,
    },
  },

  emits: ['handle-change', 'handle-check'],

  setup(props, { emit }) {
    const sankey = ref();
    const num = ref(10);
    const checked = ref(false);
    const option = {
      tooltip: {
        show: true,
        trigger: 'item',
        triggerOn: 'mousemove',
      },
      series: {
        left: props.type === 'flu' ? -200 : 0,
        type: 'sankey',
        data: props.dataSet.nodes,
        links: props.dataSet.links,
        focusNodeAdjacency: false,
        levels: [
          {
            depth: 0,
            itemStyle: {
              color: '#D79DCD',
            },
            lineStyle: {
              color: '#D79DCD',
            },
          },
          {
            depth: 1,
            itemStyle: {
              color: '#E3BB5B',
            },
            lineStyle: {
              color: '#E3BB5B',
            },
          },
          {
            depth: 2,
            itemStyle: {
              color: '#DCC1C6',
            },
            lineStyle: {
              color: '#DCC1C6',
            },
          },
          {
            depth: 3,
            itemStyle: {
              color: '#CDDAA2',
            },
            lineStyle: {
              color: '#CDDAA2',
            },
          },
          {
            depth: 4,
            itemStyle: {
              color: '#ABB1E1',
            },
            lineStyle: {
              color: '#ABB1E1',
            },
          },
          {
            depth: 5,
            itemStyle: {
              color: '#D1D7A7',
            },
            lineStyle: {
              color: '#D1D7A7',
            },
          },
          {
            depth: 6,
            itemStyle: {
              color: '#4F5297',
            },
            lineStyle: {
              color: '#4F5297',
            },
          },
        ],
      },
    };

    const getLegend = () => {
      const svg = d3.select('#legend').append('svg').attr('height', 30);
      svg.call(legend);
    };

    const highlightText = () => {
      const el = d3.select('.sankey').selectAll('tspan');
      const arr1 = props.sankeyType['致病源'];
      const arr2 = props.sankeyType['条件致病源'];
      el._groups[0].forEach((item: any) => {
        arr1.forEach((j: any) => {
          if (item.textContent.indexOf(j) > -1) {
            item.setAttribute('fill', colors[0]);
          }
        });
        arr2.forEach((j: any) => {
          if (item.textContent.indexOf(j) > -1) {
            item.setAttribute('fill', colors[1]);
          }
        });
      });
    };

    const init = () => {
      const chartInstance = echarts.init(unref(sankey), { renderer: 'svg' });
      chartInstance.setOption(option);
      setTimeout(() => {
        highlightText();
      }, 1000);
      window.onresize = () => {
        chartInstance.resize();
      };
    };

    // 切换最小值
    const handleChange = (value: any) => {
      emit('handle-change', value);
    };

    // 默认第九层选项
    const handleCheck = (value: any) => {
      emit('handle-check', value);
    };

    onMounted(() => {
      getLegend();
    });

    onUnmounted(() => {
      window.onresize = null;
    });

    watch(props.dataSet, () => {
      Object.assign(option.series, {
        data: props.dataSet.nodes,
        links: props.dataSet.links,
      });
      init();
    });

    return {
      sankey,
      num,
      checked,
      handleChange,
      handleCheck,
    };
  },
});
</script>

<style lang="less" scoped>
.main {
  margin: auto;
  position: relative;
  z-index: 9;
}

.input-container {
  position: absolute;
  left: 20px;
  top: 30px;
  display: flex;
  align-items: center;
  z-index: 99;

  div {
    &:first-child {
      margin-right: 20px;
    }
  }
}

.tip {
  position: absolute;
  left: 20px;
  font-size: 14px;
  display: inline-flex;
  word-break: keep-all;
  min-width: 340px;
}

.sankey {
  position: absolute;

  &-margin-top {
    top: 60px;
  }
}
</style>